﻿using AForge.Video.DirectShow;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace 人脸识别技术
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
                SetBtnStatus(false);
            }
        public enum TEMUM_FEATURE_ID
        {
            ZKFACE_FEATURE_ID_UNKNOWN = -1                //未知的面部特征
        }

        public enum ZKFACE_ICaoFEATUREID
        {
            ZKFACE_ICAO_FEATURE_ID_AGE = 0,
            ZKFACE_ICAO_FEATURE_ID_GENDR = 1,
            ZKFACE_ICAO_FEATURE_QUALITY = 2                    // 获取面部的质量
        }
        [DllImport("./ZKLiveFace.dll")]
        extern static int ZKLiveFace_Version(byte[] version, ref int size);

        [DllImport("./ZKLiveFace.dll")]
        extern static int ZKLiveFace_LoadImage(string FileName, byte[] rawImage, ref int width, ref int height, ref int size);

        [DllImport("./ZKLiveFace.dll")]
        extern static int ZKLiveFace_LoadImageFromMemory(byte[] ImageFileData, byte[] rawImage, ref int width, ref int height, ref int size);

        [DllImport("./ZKLiveFace.dll")]
        extern static int ZKLiveFace_LoadImageFromMemoryExt(byte[] ImageFileData, int cbImageFileData, byte[] rawImage, ref int width, ref int height, ref int size);
        [DllImport("./ZKLiveFace.dll")]
        extern static int ZKLiveFace_Init(ref IntPtr context);

        [DllImport("./ZKLiveFace.dll")]
        extern static int ZKLiveFace_SetParamter(IntPtr context, int code, byte[] value, int size);

        [DllImport("./ZKLiveFace.dll")]
        extern static int ZKLiveFace_GetParamter(IntPtr context, int code, byte[] value, ref int size);

        [DllImport("./ZKLiveFace.dll")]
        extern static int ZKLiveFace_DetectFaces(IntPtr context, byte[] rawImage, int width, int height, ref int detectedFaces);

        [DllImport("./ZKLiveFace.dll")]
        extern static int ZKLiveFace_Terminate(IntPtr context);

        [DllImport("./ZKLiveFace.dll")]
        extern static int ZKLiveFace_GetFaceContext(IntPtr context, int faceIdx, ref IntPtr faceContext);

        [DllImport("./ZKLiveFace.dll")]
        extern static int ZKLiveFace_GetFaceICaoFeature(IntPtr faceContext, ZKFACE_ICaoFEATUREID featureID, ref int score);

        [DllImport("./ZKLiveFace.dll")]
        extern static int ZKLiveFace_ExtractTemplate(IntPtr faceContext, byte[] template, ref int size, ref int resverd);

        [DllImport("./ZKLiveFace.dll")]
        extern static int ZKLiveFace_GetFaceRect(IntPtr context, int faceIndex, int[] points, int len);

        [DllImport("./ZKLiveFace.dll")]
        extern static int ZKLiveFace_GetFaceRect2(IntPtr context, int[] points, int len);

        [DllImport("./ZKLiveFace.dll")]
        extern static int ZKLiveFace_Verify(IntPtr context, byte[] regTemplage, int cbRegTemplate, byte[] verTemplate, int cbVerTemplate, ref int score);

        [DllImport("./ZKLiveFace.dll")]
        extern static int ZKLiveFace_GetLastError(IntPtr contex, byte[] lasterror, ref int size);


        IntPtr g_context = IntPtr.Zero; //算法库指针

        byte[] g_regTemplate = new byte[1024];
        byte[] g_verTemplate = new byte[1024];

        bool g_bInit = false;  //初始化标志

        public void SetBtnStatus(bool flag)
        {
            //this.BTN_ENROLL.IsEnabled = flag;
            //BTN_VERIFY.IsEnabled = flag;
            //BTN_GETVERTMP.IsEnabled = flag;
            //BTN_TERMINATE.IsEnabled = flag;
            //if (flag)
            //{
            //    BTN_INIT.IsEnabled = false;
            //}
            //else
            //{
            //    BTN_INIT.IsEnabled = true;
            //}
        }
        public void GetFilePath(ref string filePathName)
        {
            OpenFileDialog fd = new OpenFileDialog();
            fd.Filter = "图像文件(*.jpg;*.gif;*.bmp;*.png)|*.jpg;*.gif;*.bmp;*.png";
            if (fd.ShowDialog() == true)
            {
                filePathName = fd.FileName;
            }

        }
        //初始化资源
        private void BTN_INIT_Click(object sender, RoutedEventArgs e)
        {
            int ret = 0;
            if (g_bInit == false)
            {
                /*初始化算法库*/
                ret = ZKLiveFace_Init(ref g_context);
                if (0 == ret)
                {
                    g_bInit = true;
                    this.EDIT_SHOWINFO.Text = "Init success";
                    SetBtnStatus(true);
                }
                else
                {
                    g_bInit = false;
                }
            }
            else
            {
                ret = 0;
            }

            if (0 == ret)
            {
                this.EDIT_SHOWINFO.Text = "Init success";
                SetBtnStatus(true);
            }
        }

        private void BTN_TERMINATE_Click(object sender, RoutedEventArgs e)
        {
            Array.Clear(g_regTemplate, 0, g_regTemplate.Length);
            Array.Clear(g_verTemplate, 0, g_verTemplate.Length);

            this.EDIT_SHOWINFO.Text = "Terminate success";
            SetBtnStatus(false);




        }

        private void BTN_ENROLL_Click(object sender, RoutedEventArgs e)
        {
            //获取要登记的人脸图像
            string filePathName = "";
            GetFilePath(ref filePathName);
            Array.Clear(g_regTemplate, 0, g_regTemplate.Length);
            int rawwidth = 0;
            int rawheight = 0;
            int rawImgSize = 0;
            IntPtr RegfaceContext = IntPtr.Zero;
            /*从图片文件转原始图像数据*/ //获取需要分配的内存大小
            int ret = ZKLiveFace_LoadImage(filePathName, null, ref rawwidth, ref rawheight, ref rawImgSize);
            if (0 == ret)
            {
                //
                byte[] regrawImage = new byte[rawImgSize]; //存放登记的原始图像
                int detectedFaces = 0;
                ret = ZKLiveFace_LoadImage(filePathName, regrawImage, ref rawwidth, ref rawheight, ref rawImgSize);
                if (0 != ret)
                {
                    this.EDIT_SHOWINFO.Text = "Login fail ZKLiveFace_LoadImage() error =" + ret;
                    return;
                }
                /*探测人脸，获取人脸数*/
                ret = ZKLiveFace_DetectFaces(g_context, regrawImage, rawwidth, rawheight, ref detectedFaces);
                if (0 != ret || detectedFaces <= 0)
                {
                    this.EDIT_SHOWINFO.Text = "Login fail ZKLiveFace_DetectFaces() error =" + ret;
                    return;
                }
                //获取单个人脸实例指针
                ret = ZKLiveFace_GetFaceContext(g_context, 0, ref RegfaceContext);
                if (0 != ret)
                {
                    this.EDIT_SHOWINFO.Text = "Login fail GetFaceContext() error =" + ret;
                    return;
                }
                int resverd = 0;
                int rawTemplateSize = 1024;
                //提取人脸模板
                ret = ZKLiveFace_ExtractTemplate(RegfaceContext, g_regTemplate, ref rawTemplateSize, ref resverd);
                if (0 != ret)
                {
                    this.EDIT_SHOWINFO.Text = "Login fail ExtractTemplate() error =" + ret;
                    return;
                }
                this.EDIT_SHOWINFO.Text = "Login success";
            }
            else
            {
                this.EDIT_SHOWINFO.Text = "Login fail LoadImage() error = " + ret;
            }
        }

        private void BTN_GETVERTMP_Click(object sender, RoutedEventArgs e)
        {
            //获取要比对的人脸图像
            string filePathName = "";
            //GetFilePath(ref filePathName);
            Array.Clear(g_verTemplate, 0, g_verTemplate.Length);
            int rawwidth = 0;
            int rawheight = 0;
            int rawImgSize = 0;
            IntPtr VerfaceContext = IntPtr.Zero;   //要比对的人脸指针

            /*从图片文件转原始图像数据*/
            //获取需要分配的内存大小
            //int ret = ZKLiveFace_LoadImage(filePathName, null, ref rawwidth, ref rawheight, ref rawImgSize);
            System.Drawing.Bitmap bitmap = (System.Drawing.Bitmap)vsp.GetCurrentVideoFrame();
            //获取二进制流
            MemoryStream ms = new MemoryStream();
            bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
            byte[] arr = new byte[ms.Length];
            ms.Position = 0;
            ms.Read(arr, 0, (int)ms.Length);
            ms.Flush();
            ms.Close();

            int ret = ZKLiveFace_LoadImageFromMemoryExt(arr, arr.Length, null, ref rawwidth, ref rawheight, ref rawImgSize);
            if (0 == ret)
            {
                int detectedFaces = 0;
                byte[] verrawImage = new byte[rawImgSize];    //要比对的人脸原始图像
                /*从图片文件转原始图像数据*/
                //ret = ZKLiveFace_LoadImage(filePathName, verrawImage, ref rawwidth, ref rawheight, ref rawImgSize);
                //WriteableBitmap wb1 = new WriteableBitmap((BitmapSource)System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                //            vsp.GetCurrentVideoFrame().GetHbitmap(),
                //            IntPtr.Zero,
                //            Int32Rect.Empty,
                //            BitmapSizeOptions.FromWidthAndHeight(1920, 1080)));
                //byte[] image_data1 = SourceToArray(wb);

                ret = ZKLiveFace_LoadImageFromMemoryExt(arr, arr.Length, verrawImage, ref rawwidth, ref rawheight, ref rawImgSize);
                if (0 != ret)
                {
                    this.EDIT_SHOWINFO.Text = "Login fail ZKLiveFace_LoadImage() error =" + ret;
                    return;
                }

                /*探测人脸，获取人脸数*/
                ret = ZKLiveFace_DetectFaces(g_context, verrawImage, rawwidth, rawheight, ref detectedFaces);
                if (0 != ret || detectedFaces <= 0)
                {
                    this.EDIT_SHOWINFO.Text = "Login fail ZKLiveFace_DetectFaces() error =" + ret;
                    return;
                }

                /*获取单个人脸实例指针*/
                ret = ZKLiveFace_GetFaceContext(g_context, 0, ref VerfaceContext);
                if (0 != ret)
                {
                    this.EDIT_SHOWINFO.Text = "Login fail GetFaceContext() error =" + ret;
                    return;
                }

                int resverd = 0;
                int rawTemplateSize = 1024;
                /*提取人脸模板*/
                ret = ZKLiveFace_ExtractTemplate(VerfaceContext, g_verTemplate, ref rawTemplateSize, ref resverd);
                if (0 != ret)
                {
                    this.EDIT_SHOWINFO.Text = "Login fail ExtractTemplate() error =" + ret;
                    return;
                }
                this.EDIT_SHOWINFO.Text = "Login success";
            }

            else
            {
                this.EDIT_SHOWINFO.Text = "Login fail LoadImage() error = " + ret;
            }
        }

        private void BTN_VERIFY_Click(object sender, RoutedEventArgs e)
        {
            int score = 0;
            /*人脸模板1:1比对*/
            int ret = ZKLiveFace_Verify(g_context, g_regTemplate, 1024, g_verTemplate, 1024, ref score);
            if (0 == ret)
            {
                this.EDIT_SHOWINFO.Text = "Verify success,score = " + score;
            }
            else
            {
                this.EDIT_SHOWINFO.Text = "Verify fail error = " + ret + ",score = " + score;
            }
        }

        private void ComboBoxVideoDevices_DropDownOpened(object sender, EventArgs e)
        {
            comboBoxVideoDevices.ItemsSource = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            comboBoxVideoDevices.DisplayMemberPath = "Name";
        }

        private void Border_MouseEnter(object sender, MouseEventArgs e)
        {
            if (Cursor != Cursors.Wait)
            {
                this.Cursor = Cursors.Hand;
            }
        }

        private void Border_MouseLeave(object sender, MouseEventArgs e)
        {
            if (Cursor != Cursors.Wait)
            {
                this.Cursor = Cursors.Arrow;
            }
        }

        private void BorderPlay_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            try
            {
                if (IconPlay.Kind == MaterialDesignThemes.Wpf.PackIconKind.Play)
                {
                    if (comboBoxVideoDevices.SelectedIndex != -1)
                    {   // 开启视频
                        vsp.VideoSource = new VideoCaptureDevice(((FilterInfo)comboBoxVideoDevices.SelectedItem).MonikerString);
                        vsp.Start();
                        if (vsp.IsRunning)
                        {
                            IconPlay.Kind = MaterialDesignThemes.Wpf.PackIconKind.Stop;
                            (IconPlay.Parent as Border).Background = Brushes.Tomato;
                        }
                    }
                }
                else
                {
                    if (vsp.IsRunning)
                    {   // 停止视频
                        vsp.SignalToStop();
                        vsp.WaitForStop();

                    }
                    IconPlay.Kind = MaterialDesignThemes.Wpf.PackIconKind.Play;
                    (IconPlay.Parent as Border).Background = Brushes.YellowGreen;
                }
            }
            catch (Exception ex)
            {
                HandyControl.Controls.Growl.Error(ex.Message);
            }
        }

        private void BorderPhoto_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            try
            {
                // 判断视频设备是否开启
                if (vsp.IsRunning)
                {   // 进行拍照
                    //if (TabControl1.SelectedIndex == 0)
                    //{
                    image1.Source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                        vsp.GetCurrentVideoFrame().GetHbitmap(),
                        IntPtr.Zero,
                        Int32Rect.Empty,
                        BitmapSizeOptions.FromWidthAndHeight(1920, 1080));
                    PackIcon1.Foreground = Brushes.Green;
                    //System.Drawing.Bitmap bitmap = (System.Drawing.Bitmap)System.Drawing.Image.FromFile(path).Clone();
                    //System.Drawing.Bitmap bitmap = (System.Drawing.Bitmap)System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                    //        vsp.GetCurrentVideoFrame().GetHbitmap(),
                    //        IntPtr.Zero,
                    //        Int32Rect.Empty,
                    //        BitmapSizeOptions.FromWidthAndHeight(1920, 1080)) ;
                    //System.Drawing.Bitmap bitmap = (System.Drawing.Bitmap)vsp.GetCurrentVideoFrame();
                    ////获取二进制流
                    //MemoryStream ms = new MemoryStream();
                    //bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
                    //byte[] arr = new byte[ms.Length];
                    //ms.Position = 0;
                    //ms.Read(arr, 0, (int)ms.Length);
                    //ms.Flush();
                    //ms.Close();
                    //}
                    //if (TabControl1.SelectedIndex == 1)
                    //{
                    //    image2.Source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                    //        vsp.GetCurrentVideoFrame().GetHbitmap(),
                    //        IntPtr.Zero,
                    //        Int32Rect.Empty,
                    //        BitmapSizeOptions.FromWidthAndHeight(1920, 1080));
                    //    PackIcon2.Foreground = Brushes.Green;
                    //}
                    //SavePic("123", "123");
                }
            }
            catch (Exception ex)
            {
                HandyControl.Controls.Growl.Error(ex.Message);
            }
        }
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (vsp.IsRunning)
            {   // 停止视频
                vsp.SignalToStop();
                vsp.WaitForStop();
            }
        }

        private void Window_Closed(object sender, EventArgs e)
        {
            Environment.Exit(0);
        }
        public static byte[] SourceToArray(WriteableBitmap source)
        {
            byte[] byteArray = null;
            try
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    JpegBitmapEncoder coder = new JpegBitmapEncoder();
                    coder.QualityLevel = 100;
                    coder.Frames.Add(BitmapFrame.Create(source));
                    coder.Save(ms);
                    byteArray = ms.ToArray();
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message.ToString());
            }
            return byteArray;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {

            string filePathName = "";
            //GetFilePath(ref filePathName);
            Array.Clear(g_verTemplate, 0, g_verTemplate.Length);
            int rawwidth = 0;
            int rawheight = 0;
            int rawImgSize = 0;
            IntPtr VerfaceContext = IntPtr.Zero;   //要比对的人脸指针

            /*从图片文件转原始图像数据*/
            //获取需要分配的内存大小
            //int ret = ZKLiveFace_LoadImage(filePathName, null, ref rawwidth, ref rawheight, ref rawImgSize);
            System.Drawing.Bitmap bitmap = (System.Drawing.Bitmap)vsp.GetCurrentVideoFrame();
            //获取二进制流
            MemoryStream ms = new MemoryStream();
            bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
            byte[] arr = new byte[ms.Length];
            ms.Position = 0;
            ms.Read(arr, 0, (int)ms.Length);
            ms.Flush();
            ms.Close();

            int ret = ZKLiveFace_LoadImageFromMemoryExt(arr, arr.Length, null, ref rawwidth, ref rawheight, ref rawImgSize);
            if (0 == ret)
            {
                int detectedFaces = 0;
                byte[] verrawImage = new byte[rawImgSize];    //要比对的人脸原始图像
                /*从图片文件转原始图像数据*/
                //ret = ZKLiveFace_LoadImage(filePathName, verrawImage, ref rawwidth, ref rawheight, ref rawImgSize);
                //WriteableBitmap wb1 = new WriteableBitmap((BitmapSource)System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                //            vsp.GetCurrentVideoFrame().GetHbitmap(),
                //            IntPtr.Zero,
                //            Int32Rect.Empty,
                //            BitmapSizeOptions.FromWidthAndHeight(1920, 1080)));
                //byte[] image_data1 = SourceToArray(wb);

                ret = ZKLiveFace_LoadImageFromMemoryExt(arr, arr.Length, verrawImage, ref rawwidth, ref rawheight, ref rawImgSize);
                if (0 != ret)
                {
                    this.EDIT_SHOWINFO.Text = "Login fail ZKLiveFace_LoadImage() error =" + ret;
                    return;
                }

                /*探测人脸，获取人脸数*/
                ret = ZKLiveFace_DetectFaces(g_context, verrawImage, rawwidth, rawheight, ref detectedFaces);
                if (0 != ret || detectedFaces <= 0)
                {
                    this.EDIT_SHOWINFO.Text = "Login fail ZKLiveFace_DetectFaces() error =" + ret;
                    return;
                }

                /*获取单个人脸实例指针*/
                ret = ZKLiveFace_GetFaceContext(g_context, 0, ref VerfaceContext);
                if (0 != ret)
                {
                    this.EDIT_SHOWINFO.Text = "Login fail GetFaceContext() error =" + ret;
                    return;
                }

                int resverd = 0;
                int rawTemplateSize = 1024;
                /*提取人脸模板*/
                ret = ZKLiveFace_ExtractTemplate(VerfaceContext, g_verTemplate, ref rawTemplateSize, ref resverd);
                if (0 != ret)
                {
                    this.EDIT_SHOWINFO.Text = "Login fail ExtractTemplate() error =" + ret;
                    return;
                }
                this.EDIT_SHOWINFO.Text = "Login success";
            }

            else
            {
                this.EDIT_SHOWINFO.Text = "Login fail LoadImage() error = " + ret;
            }
            int score = 0;
            /*人脸模板1:1比对*/
            int ret1 = ZKLiveFace_Verify(g_context, g_regTemplate, 1024, g_verTemplate, 1024, ref score);
            if (0 == ret1)
            {
                this.EDIT_SHOWINFO.Text = "Verify success,score = " + score;
            }
            else
            {
                this.EDIT_SHOWINFO.Text = "Verify fail error = " + ret1 + ",score = " + score;
            }

        }


        //private void Demo_cs_FormClosing(object sender, FormClosingEventArgs e)
        //{
        //    if (g_context != IntPtr.Zero)
        //    {
        //        /*释放算法库*/
        //        ZKLiveFace_Terminate(g_context);
        //    }
        //}
    }
}
